//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <limits.h>
#include <ctype.h>
#include <eladef.h>

extern "C" int __cdecl wcsnicmp( const wchar_t* str1,
                                 const wchar_t* str2,
                                 unsigned int count)
{
    int c1, c2;
    if (count) {
        do {
            c1 = *str1++;
            if (c1 >= 'A' && c1 <= 'Z') // convert to lower case.
                c1 -= 'A' - 'a';

            c2 = *str2++;
            if (c2 >= 'A' && c2 <= 'Z') // convert to lower case.
                c2 -= 'A' - 'a';
        } while (--count && c1 && (c1 == c2));
        return (c1 - c2);
    }
    return 0;

}

extern "C" int isupper (int c)
{
    return (c >= 'A' && c <= 'Z');
}

extern "C" int isalpha(int c)
{
    return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}

extern "C" int isdigit(int c)
{
    return (c >= '0' && c <= '9');
}

extern "C" int __isascii(int c)
{
    return !(c & 0xFFFFFF80);
}

extern "C" int isspace(int c)
{
    return (c == ' ');
}

/*
 * Convert a string to a long integer.
 */
extern "C" long __cdecl wcstol(const wchar_t * nptr, wchar_t ** endptr, int base)
{
    register const wchar_t * s = nptr;
    register unsigned long acc;
    register wchar_t c;
    register unsigned long cutoff;
    register int neg = 0;
    register int any, cutlim;
    register int temp;
    const wchar_t *start = nptr;

    /*
     * Skip white space and pick up leading +/- sign if any.
     * If base is 0, allow 0x for hex and 0 for octal, else
     * assume decimal; if base is already 16, allow 0x.
     */
    if (base > 36 || base == 1 || nptr == 0) {
        if (endptr) {
            *endptr = (wchar_t *) start;
        }
        return(0L);
    }

    do {
        c = *s++;
    } while (isspace(c));
    if (c == L'-') {
        neg = 1;
        c = *s++;
    }
    else if (c == L'+')
        c = *s++;
    if ((base == 0 || base == 16) && c == L'0' && (*s == L'x' || *s == L'X')) {
        c = s[1];
        s += 2;
        base = 16;
    }
    if (base == 0) base = c == L'0' ? 8 : 10;

    /*
     * Compute the cutoff value between legal numbers and illegal
     * numbers.  That is the largest legal value, divided by the
     * base.  An input number that is greater than this value, if
     * followed by a legal input character, is too big.  One that
     * is equal to this value may be valid or not; the limit
     * between valid and invalid numbers is then based on the last
     * digit.  For instance, if the range for longs is
     * [-2147483648..2147483647] and the input base is 10,
     * cutoff will be set to 214748364 and cutlim to either
     * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
     * a value > 214748364, or equal but the next digit is > 7 (or 8),
     * the number is too big, and we will return a range error.
     *
     * Set any if any `digits' consumed; make it negative to indicate
     * overflow.
     */
    cutoff = LONG_MAX + neg;
    cutlim = LONG_MAX % (long)base + neg;
    cutoff /= (long)base;
    for (acc = 0, any = 0;; c = *s++) {
        if (!__isascii(c)) break;
        if (isdigit(c))
            c -= L'0';
        else if (isalpha(c))
            c -= isupper(c) ? L'A' - 10 : L'a' - 10;
        else
            break;
        if (c >= (wchar_t)base) break;
        if (any < 0 || acc > cutoff || (acc == cutoff && c > (wchar_t)cutlim))
            any = -1;
        else {
            any = 1;
            acc *= base;
            acc += c;
        }
    }
    if (any < 0) {
        acc = neg ? LONG_MIN : LONG_MAX;
        //return 0;
    }
    else if (neg) {
        temp = 0 - acc;
        acc = (unsigned)temp;
    }
    if (endptr != 0)
        *endptr = (wchar_t *)(any ? s - 1 : nptr);
    return (acc);
}

extern "C" size_t __cdecl wcstombs(char *str, const wchar_t *wcs, size_t len)
{
    size_t count = 0;
    if (wcs == 0 || str == 0) {
        return 0;
    }
    while (*wcs && count < len) {
//        if ((unsigned int)*wcs > 127)
//            _assert("_wcstombs fault, transfer error WCHAR!\n", __FILE__, __LINE__);
        *str ++ = (char)*wcs ++;
        count ++;
    }
    *str = '\0';
    return count;
}

extern "C" size_t __cdecl mbstowcs(wchar_t *wcs, const char *str, size_t len)
{
    size_t count = 0;
    if (wcs == 0 || str == 0) {
        return 0;
    }
    while (*str && count < len) {
//        if ((unsigned int)*wcs > 127)
//            _assert("_wcstombs fault, transfer error WCHAR!\n", __FILE__, __LINE__);
        *wcs ++ = (wchar_t)*str ++;
        count ++;
    }
    *wcs = '\0';
    return count;
}

extern "C" int __cdecl sprintf(char *, const char *,...)
{
    return 0;
}

extern "C" void _assert(const char *exp, const char *f, int ln)
{
   // printf("Assertion failed: %s, file %s, line %d\n", exp, f, ln);

    DebugBreak();

    return ;
}

typedef unsigned char  u8;
extern "C" void * memset(void *dest, int c, size_t n)
{
    u8 *tmp = (u8 *)dest;

    while (n--> 0)
        *tmp++ = (u8)c;

    return dest;
}


extern "C"  void * __cdecl memcpy(void * pDest, const void * pSource, size_t cb)
{
#ifdef _GNUC

#if defined(_x86)
    int temp0, temp1, temp2;
    ASM("rep;"
        "movsd;"//movs DoubleWord(4 btyes) one time
        "testb $2,%b6;"//0x03H--11b, 0x02H--10b, 0x01H--01b
        "je 1f;"
        "movsw;"
        "1:"
        "testb $1,%b6;"
        "je 2f;"
        "movsb;"
        "2:"
        :"=D" (temp0), "=S" (temp1), "=c" (temp2)
        :"0" ((long)pDest),"1" ((long)pSource), "2" (cb/4), "a" (cb)
        :"memory");
    return pDest;
#endif    //if defined(_x86)

#endif    //ifdef _GNUC

    if (((int)pDest | (int)pSource | cb) & (sizeof(void*)-1)) {
        char* p = (char*) pDest;    // not natural aligned
        char* q = (char*) pSource;
        while (cb--) {
            *p++ = *q++;            // copy one byte at a time
        }
    }
    else {                          // in case of natural alignment
        int* p = (int*) pDest;
        int* q = (int*) pSource;
        int count = cb / sizeof(int);
//        assert(sizeof(int) == 4);   // NOTE: modify for 64 bit machine later

        while (count--) {
            *p++ = *q++;            // copy 4 bytes at a time
        }
    }
    return pDest;
}    

extern "C" void* __cdecl memmove(void* pDest, const void* pSource, size_t count)
{
#ifdef _GNUC

#if defined(_x86)
    int temp0, temp1, temp2;
    if (pDest < pSource) {
        ASM("rep;"
            "movsd;"//movs DoubleWord(4 btyes) one time
            "testb $2,%b6;"//0x03H--11b, 0x02H--10b, 0x01H--01b
            "je 1f;"
            "movsw;"
            "1:"
            "testb $1,%b6;"
            "je 2f;"
            "movsb;"
            "2:"
            :"=D" (temp0), "=S" (temp1), "=c" (temp2)
            :"0" ((long)pDest),"1" ((long)pSource), "2" (count / 4), "a" (count)
            : "memory");
    }
    else {
        ASM("std;"//set DF=1
            "cmp $4, %6;"
            "js 1f;"
            "sub $4, %0;"
            "sub $4, %1;"
            "rep;"
            "movsd;"
            "add $4, %0;"
            "add $4, %1;"
            "1:"
            "sub $1, %0;"
            "sub $1, %1;"
            "movl %7, %2;"
            "rep;"
            "movsb;"
            "cld;"//reset DF=0
            :"=D" (temp0), "=S" (temp1), "=c" (temp2)
            :"0" ((long)pDest + count),
             "1" ((long)pSource + count),
             "2" (count / 4),
             "a" (count),
             "d" (count % 4)
            :"memory");
    }
    return pDest;
#endif    //if defined(_x86)

#endif    //ifdef _GNUC

    _ELASTOS Boolean naturalAlignment;
    int delta;
    unsigned long i;
    void* pRet = pDest;

    if (((unsigned long)pSource | (unsigned long)pDest | count) & (sizeof(void*)-1)) {
        delta = 1;                      // copy one byte at a time
        naturalAlignment = FALSE;
    }
    else {
        delta = sizeof(int);            // natural alignment size
        count /= sizeof(int);           // copy this many machine words
        naturalAlignment = TRUE;
    }

    if (pDest > pSource) {              // copy in descending order
        int offset = count * delta - delta;
        pSource = (void*)((byte*)pSource + offset);
        pDest = (void*)((byte*)pDest + offset);
        delta = -delta;
    }

    if (naturalAlignment) {
        for (i = 0; i < count; i++) {   // copy one machine word at a time
            *((int*) pDest) = *((int*) pSource);
            pDest = (void*)((byte*)pDest + delta);
            pSource = (void*)((byte*)pSource + delta);
        }
    }
    else {
        for (i = 0; i < count; i++) {   // copy one byte at a time
            *((byte*) pDest) = *((byte*) pSource);
            pDest = (void*)((byte*)pDest + delta);
            pSource = (void*)((byte*)pSource + delta);
        }
    }

    return pRet;
}

extern "C" int wcscmp (const wchar_t* str1, const wchar_t* str2)
{
    register int result;

#ifdef _GNUC

#if defined(_x86)
    int temp0, temp1;
    ASM("1:"
        "lodsw;"
        "scasw;"
        "jne 2f;"
        "testw %%ax,%%ax;"
        "jne 1b;"
        "xorl %%eax,%%eax;"
        "jmp 3f;"
        "2:"
        "sbbl %%eax,%%eax;"
        "orw $1,%%ax;"
        "3:"
        :"=a"(result), "=S" (temp0), "=D" (temp1)
        :"1" (str1), "2" (str2));

    return result;
#endif    //if defined(_x86)

#endif    //ifdef _GNUC

    do {
        result = *str1 - *str2;
        str1++;
    } while (result == 0 && *str2++!= '\0');

    return result;

} 

extern "C" wchar_t* wcscpy (wchar_t* dest, const wchar_t* source)
{
#ifdef _GNUC

#if defined(_x86)
    int temp0, temp1, temp2;
    ASM("1:"
        "lodsw;"
        "stosw;"
        "testw %%ax, %%ax;"
        "jne 1b;"
        :"=D" (temp0), "=S" (temp1), "=a" (temp2)
        :"0" (dest), "1" (source)
        :"memory");
    return dest;
#endif    //if defined(_x86)

#endif    //ifdef _GNUC

    register size_t i = 0;
    while (source[i]) {dest[i] = source[i]; i++;}
    dest[i] = 0;
    return dest;
}

extern "C" int __cdecl _wtoi(const wchar_t * string)
{
    int v = 0;
    int neg = 0;
    wchar_t c;

    if (!string) return 0;

    do {
        c = *string++;
    } while (isspace(c));

    if (c == '+')
        c = *string++;
    else if (c == '-') {
        neg = 1;
        c = *string++;
    }

    for (;;) {
        if (c < '0' || c > '9')
            break;
        v = (v * 10) + (int)(c - '0');
        c = *string++;
    }

    if(neg == 1) v = 0 - v;
    return v;

}

extern "C" size_t strlen(const char * str)
{
#ifdef _GNUC

#if defined(_x86)
    int temp;
    register int count;
    ASM("repne;"
        "scasb;"
        "notl %1;"
        "decl %1;"//not include '\0'
        :"=D" (temp), "=c" (count)
        :"0" (str), "a" (0x0), "1" (0xffffffffu));
    return count;
#endif    //if defined(_x86)

#endif    //ifdef _GNUC

    const char *p = str;
    while (*p) p++;
    return (size_t)(p - str);
}

extern "C" size_t wcslen(const wchar_t * str)
{
#ifdef _GNUC

#if defined(_x86)
    int temp;
    register int count;
    ASM("repne;"
        "scasw;"
        "notl %1;"
        "decl %1;"//not include '\0'
        :"=D" (temp), "=c" (count)
        :"0" (str), "a" (0x0), "1" (0xffffffffu));
    return count;
#endif    //if defined(_x86)

#endif    //ifdef _GNUC

    register size_t i = 0;
    while (str[i]) i++;
    return i;
}        

extern "C" int __cdecl wcsncmp(const wchar_t* pStr1, const wchar_t* pStr2, size_t count)
{
    if (!count)
        return 0;

    while (--count && *pStr1 && *pStr1 == *pStr2) {
        pStr1++;
        pStr2++;
    }

    return *(unsigned char *)pStr1 - *(unsigned char *)pStr2;
}

	
extern "C" wchar_t* wcsstr(const wchar_t * string, const wchar_t * strCharSet)
{
    if (*strCharSet != '\0') {
        wchar_t sub = *strCharSet++;
        size_t len = wcslen(strCharSet);
        do {
            wchar_t ch;
            do {
                ch = *string++;
                if (ch == 0)
                    return NULL;
            } while (ch != sub);

            if (len == 0)
                return ((wchar_t *)(string-1));
        } while (wcsncmp(string, strCharSet, len));
        string--;
    }
    return ((wchar_t *)string);
}

extern "C" wchar_t* __cdecl wcscat(wchar_t* pDest, const wchar_t* pSource)
{
#ifdef _GNUC

#if defined(_x86)
    int temp0, temp1, temp2, temp3;
    ASM("repne;"
        "scasw;"
        "sub $2, %0;"//edi=edi-2
        "1:"
        "lodsw;"
        "stosw;"
        "testw %%ax,%%ax;"
        "jne 1b;"
        : "=D" (temp0), "=S" (temp1), "=a" (temp2), "=c" (temp3)
        : "0" (pDest), "1" (pSource), "2" (0), "3" (0xffffffffu)
        :"memory");

    return pDest;
#endif    //if defined(_x86)

#endif    //if _GNUC

    wchar_t* p;
    for (p = pDest; *p != 0;++p) // find end of pDest
        ;
    while ((*p++= *pSource++) != 0) // copy pSource to end of pDest
        ;
    return pDest;
}


#ifdef _MSVC

extern "C" int _fltused = 0x9875;       // required by VC6.0

extern "C" int  __cdecl _purecall(void)
{
	DebugBreak();
	return 0;
}

extern "C"  __declspec(naked)  void __cdecl _ftol2(void)
{
    __asm {
        push        ebp
        mov         ebp, esp
        sub         esp, 12

        fwait                           // check for pending numeric exceptions
        fnstcw      [ebp-2]             // write FPU control word to memory
        fwait

        mov         ax, [ebp-2]
        or          ah, 12
        mov         [ebp-4],ax

        fldcw       [ebp-4]             // replaces current FPU control word
        fistp       qword ptr [ebp-12]  // store integer
        fldcw       [ebp-2]

        mov         eax, [ebp-12]
        mov         edx, [ebp-8]

        leave
        ret
	}
}

#endif
